{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Third attempt at learning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import plotly\n",
    "import plotly.graph_objs as go\n",
    "plotly.offline.init_notebook_mode()\n",
    "import os\n",
    "import random\n",
    "import math\n",
    "from tqdm import tqdm\n",
    "from sklearn.metrics import mean_squared_error\n",
    "from sklearn.decomposition import PCA\n",
    "from scipy.stats import spearmanr\n",
    "import pymc3 as pm\n",
    "import theano\n",
    "import datetime\n",
    "theano.config.compute_test_value = 'raise'\n",
    "%matplotlib inline\n",
    "from multiprocessing import Pool, cpu_count\n",
    "from functools import partial"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "SELECTED_DATA_DIR = \"../selected-data/\"\n",
    "MOVIES_FILE = \"best_movie_ratings_features_engineered.csv\"\n",
    "USERS_FILE = \"users_ratings.csv\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Read raw data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "movies_raw = pd.read_csv(SELECTED_DATA_DIR + MOVIES_FILE, index_col=0)\n",
    "movies_raw.rating = movies_raw.rating/10\n",
    "movies_raw.sample()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "users = pd.read_csv(SELECTED_DATA_DIR + USERS_FILE, index_col=0)\n",
    "users.rating = users.rating/10\n",
    "users.sample()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "users.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reduce data dimension (PCA)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "WANTED_DIM = 20"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "pca_df = movies_raw[list(movies_raw.columns[2:])]\n",
    "pca = PCA(n_components=WANTED_DIM)\n",
    "pca_df = pd.DataFrame(pca.fit_transform(pca_df))\n",
    "pca_df.index = movies_raw.index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "movies_raw.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Pourcentage of variance in dataset conserveted"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "pca.explained_variance_ratio_.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "movies = pd.concat([movies_raw[list(movies_raw.columns[:2])], pd.DataFrame(pca_df)] ,axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Collaborative data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "collabo = movies.merge(users, left_index=True, right_index=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "for n in range(WANTED_DIM):\n",
    "    collabo[n] = (collabo[n] * collabo['rating_x'])* collabo['rating_x'] # fois le rating au carre"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "collabo = collabo.groupby(collabo.user).aggregate(np.average)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "for n in range(WANTED_DIM):\n",
    "    collabo[n] = (collabo[n] * collabo['rating_x']) # fois le rating moyen pour pouvoir compare les users"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "collabo = collabo[[n for n in range(WANTED_DIM)]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "collabo.sample(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Actions selection function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class algorithm:\n",
    "    def update_features(self, user_features, movie_features, rating, t):\n",
    "        return update_features(user_features, movie_features, rating, t)\n",
    "    def compute_utility(self, user_features, movie_features, epoch, s):\n",
    "        return compute_utility(user_features, movie_features, epoch, s)\n",
    "    \n",
    "class random_choice(algorithm):\n",
    "    def choice(self, user_features, movies, epoch, s):\n",
    "        \"\"\" random approach to the problem, always exploring\"\"\"\n",
    "        return movies.sample()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def greedy_choice_t(user_features, movies, epoch, s, recommf):\n",
    "    \"\"\" greedy with decreasing epsilon \"\"\"\n",
    "    epsilon = 1 / math.sqrt(epoch+1)\n",
    "    return greedy_choice_no_t(user_features, movies, epoch, s, recommf, epsilon)\n",
    "\n",
    "def greedy_choice_no_t(user_features, movies, epoch, s, recommf, epsilon):\n",
    "    \"\"\" greedy with fixed epsilon \"\"\"\n",
    "    if random.random() > epsilon:\n",
    "        return recommf(user_features, movies, epoch, s)\n",
    "    else:\n",
    "        return movies.sample()\n",
    "    \n",
    "class greedy_choice_contentbased(algorithm):\n",
    "    def choice(self, user_features, movies, epoch, s):\n",
    "        \"\"\" greedy approach to the problem \"\"\"\n",
    "        return greedy_choice_t(user_features, movies, epoch, s, best_contentbased_recommandation)\n",
    "\n",
    "class greedy_choice_no_t_contentbased(algorithm):\n",
    "    def choice(self, user_features, movies, epoch, s, epsilon=0.3):\n",
    "        \"\"\" greedy approach to the problem \"\"\"\n",
    "        return greedy_choice_no_t(user_features, movies, epoch, s, best_contentbased_recommandation, epsilon)\n",
    "    \n",
    "class greedy_choice_UCB(algorithm):\n",
    "    def choice(self, user_features, movies, epoch, s):\n",
    "        \"\"\" greedy approach with upper confidence bounds \"\"\"\n",
    "        return greedy_choice_t(user_features, movies, epoch, s, partial(best_contentbased_recommandation, UCB=True))\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class greedy_choice_collaborative(algorithm):\n",
    "    def choice(self, user_features, movies, epoch, s):\n",
    "        \"\"\" greedy approach to the problem \"\"\"\n",
    "        return greedy_choice_t(user_features, movies, epoch, s, best_collaborative_recommandation)\n",
    "\n",
    "class greedy_choice_no_t_collaborative(algorithm):\n",
    "    def choice(self, user_features, movies, epoch, s, epsilon=0.3):\n",
    "        \"\"\" greedy approach to the problem \"\"\"\n",
    "        return greedy_choice_no_t(user_features, movies, epoch, s, best_collaborative_recommandation, epsilon)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class LinUCB(algorithm):\n",
    "    def __init__(self, alpha):\n",
    "        self.first = True\n",
    "        self.alpha = alpha\n",
    "        \n",
    "    def choice(self, user_features, movies, epoch, s):\n",
    "        # movies features\n",
    "        x = movies.apply(get_movie_features, axis=1).as_matrix()\n",
    "        # number of movies\n",
    "        m = x.shape[0]\n",
    "        # dimension of movie features\n",
    "        d = x.shape[1]\n",
    "        # initialize when first time\n",
    "        if self.first:\n",
    "            self.first = False\n",
    "            self.A = np.zeros((m, d, d))\n",
    "            for a in range(m):\n",
    "                self.A[a] = np.eye(d)\n",
    "            self.b = np.zeros((m, d))\n",
    "        # get rating for every movie\n",
    "        ratings = np.zeros(m)\n",
    "        for a, (title, movie) in enumerate(movies.iterrows()):\n",
    "            A_inv = np.linalg.inv(self.A[a])\n",
    "            theta_a = A_inv.dot(self.b[a])\n",
    "            ratings[a] = theta_a.T.dot(x[a]) + self.alpha * np.sqrt(x[a].T.dot(A_inv).dot(x[a]))\n",
    "        self.recomm = ratings.argmax()\n",
    "        chosen = movies[movies.index == movies.index[self.recomm]]\n",
    "        self.A[self.recomm] += x[self.recomm].dot(x[self.recomm].T)\n",
    "        return chosen\n",
    "    \n",
    "    def update_features(self, user_features, movie_features, rating, t):\n",
    "        self.b[self.recomm] += rating * movie_features\n",
    "        return super().update_features(user_features, movie_features, rating, t)\n",
    "    \n",
    "    def compute_utility(self, user_features, movie_features, epoch, s):\n",
    "        return user_features.dot(movie_features)\n",
    "            \n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def bayes_UCB(user_features, movies, epoch, s):\n",
    "    # Hyperparameters\n",
    "    c0 = 10\n",
    "    d0 = 3\n",
    "    e0 = 0.01\n",
    "    f0 = 0.001\n",
    "    g0 = 0.001\n",
    "    # function\n",
    "    I = np.eye(user_features.size)\n",
    "    ratings = np.zeros(movies.shape[0])\n",
    "    with pm.Model():\n",
    "        s = pm.Gamma('s', d0, e0)\n",
    "        sigma = pm.InverseGamma('sigma', f0, g0)\n",
    "        theta = pm.MvNormal('theta', mu=0.5, cov=c0 * sigma * I)\n",
    "        rating = pm.Normal('rating', mu=0, sd=sigma, observed=user_features)\n",
    "\n",
    "        for i, (title, movie) in tqdm(enumerate(movies.iterrows())): \n",
    "            movies_features = get_movie_features(movies)\n",
    "            # Expected value of outcome\n",
    "            mu = user_features.dot(movies_features) * (1 - np.exp(-epoch/s))\n",
    "            # Likelihood (sampling distribution) of observations\n",
    "            rating.mu = mu\n",
    "            \n",
    "            step = pm.Metropolis()\n",
    "            trace = pm.sample(1000, step=step, njobs=1, progressbar=False)\n",
    "            ratings[i] = rating.distribution.random()[0]\n",
    "    return movies[movies.index == movies.index[ratings.argmax()]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Learning utilities"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def compute_utility(user_features, movie_features, epoch, s):\n",
    "    \"\"\" Compute utility U based on user preferences and movie preferences \"\"\"\n",
    "    res = user_features.dot(movie_features) * (1 - math.exp(-epoch/s))\n",
    "    return res\n",
    "\n",
    "def compute_novelty(allepoch, s):\n",
    "    \"\"\" Compute utility U based on user preferences and movie preferences \"\"\"\n",
    "    res = []\n",
    "    for epoch in allepoch:\n",
    "        res.append(1 - math.exp(-epoch/s))\n",
    "    return res\n",
    "\n",
    "def compute_UCB(epoch, Nt):\n",
    "    return math.sqrt((2 * math.log2(epoch + 1)) / (Nt * epoch))\n",
    "\n",
    "def get_movie_features(movie):\n",
    "    \"\"\" selected features from dataframe \"\"\"\n",
    "    if isinstance(movie, pd.Series):\n",
    "        return movie[-WANTED_DIM:]\n",
    "    elif isinstance(movie, pd.DataFrame):\n",
    "        return get_movie_features(movie.loc[movie.index[0]])\n",
    "    else:\n",
    "        raise TypeError(\"{} should be a Series or DataFrame\".format(movie))\n",
    "        \n",
    "def iterative_mean(old, new, t):\n",
    "    \"\"\" Compute the new mean \"\"\"\n",
    "    return ((t-1) / t) * old + (1/t) * new\n",
    "    \n",
    "def update_features(user_features, movie_features, rating, t):\n",
    "    \"\"\" update the user preferences \"\"\"\n",
    "    return iterative_mean(user_features, movie_features * rating, t+1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Content based"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def best_contentbased_recommandation(user_features, movies, epoch, s, UCB=False):\n",
    "    \"\"\" Return the movie with the highest utility \"\"\"\n",
    "    utilities = np.zeros(movies.shape[0])\n",
    "    for i, (title, movie) in enumerate(movies.iterrows()):\n",
    "        movie_features = get_movie_features(movie)\n",
    "        utilities[i] = compute_utility(user_features, movie_features, epoch - movie.last_t, s)\n",
    "        if UCB:\n",
    "            utilities[i] += compute_UCB(epoch, movie.Nt)\n",
    "    return movies[movies.index == movies.index[utilities.argmax()]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Collaborative filtering"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def best_collaborative_recommandation____(user_features, user_movies, epoch, s):\n",
    "    \"\"\" Return the movie with the highest utility \"\"\"\n",
    "    corr = np.zeros(collabo.shape[0])\n",
    "    corruser = np.zeros(collabo.shape[0])\n",
    "    # TODO retirer lui-meme de la matrix collabo\n",
    "    # on fait une pearson corr avec tous les autres users -> CLUSTERING\n",
    "    for collabi, collabrow in enumerate(collabo.iterrows()):\n",
    "        otheruser_index = collabrow[0]\n",
    "        otheruser_features = collabrow[1]\n",
    "        corr[collabi] = np.correlate(user_features, otheruser_features)\n",
    "        corruser[collabi] = otheruser_index\n",
    "    # on prends les films des 5 plus proche\n",
    "    idxbestuser = []\n",
    "    for i in range(10):\n",
    "        idxmax = corr.argmax()\n",
    "        idxbestuser.append(corruser[idxmax])\n",
    "        corruser[idxmax] = 0\n",
    "    moviesbestuser = users.copy()[users.user.isin(idxbestuser)].index\n",
    "    # on fait une jointure avec les films du user\n",
    "    try:\n",
    "        subsetmovie = user_movies.copy().loc[moviesbestuser]\n",
    "        subsetmovie = subsetmovie.dropna()\n",
    "    except:\n",
    "        print(\"WARNING : no jointure btw user\")\n",
    "        return best_contentbased_recommandation(user_features, user_movies, epoch, s)\n",
    "    ## on retourne le mieux coté\n",
    "    ## TODO : verifier qu'on ne l'a pas deja vu\n",
    "    #argmaxmovie = subsetmovie['rating'].argmax()\n",
    "    #if subsetmovie.loc[argmaxmovie][0] == 'rating':\n",
    "    #    print('WTF')\n",
    "    #    print(subsetmovie.loc[argmaxmovie].name)\n",
    "    ##print(subsetmovie.loc[argmaxmovie])\n",
    "    #return subsetmovie.loc[argmaxmovie]\n",
    "    return best_contentbased_recommandation(user_features, subsetmovie, epoch, s)\n",
    "\n",
    "def best_collaborative_recommandation(user_features, user_movies, epoch, s):\n",
    "    \"\"\" Return the movie with the highest utility \"\"\"\n",
    "    corr = np.zeros(collabo.shape[0])\n",
    "    corruser = np.zeros(collabo.shape[0])\n",
    "    # on fait une pearson corr avec tous les autres users -> CLUSTERING\n",
    "    for collabi, collabrow in enumerate(collabo.iterrows()):\n",
    "        otheruser_index = collabrow[0]\n",
    "        otheruser_features = collabrow[1]\n",
    "        corr[collabi] = float(np.correlate(user_features, otheruser_features)[0])\n",
    "        corruser[collabi] = otheruser_index\n",
    "    # on prends les films des 5 plus proche\n",
    "    idxbestuser = []\n",
    "    for i in range(10):\n",
    "        idxmax = corr.argmax()\n",
    "        idxbestuser.append(corruser[idxmax])\n",
    "        corruser[idxmax] = 0\n",
    "    moviesbestuser = users.copy()[users.user.isin(idxbestuser)].index\n",
    "    # on fait une jointure avec les films du user\n",
    "    try:\n",
    "        subsetmovie = user_movies.copy().loc[moviesbestuser]\n",
    "        subsetmovie = subsetmovie.dropna()\n",
    "    except:\n",
    "        print(\"WARNING : no jointure btw user\")\n",
    "        return best_contentbased_recommandation(user_features, user_movies, epoch, s)\n",
    "    ## on retourne le mieux coté\n",
    "    subsetmovie['rating'] = subsetmovie['rating'] * compute_novelty(epoch - subsetmovie.last_t, s)\n",
    "    maxrating = subsetmovie['rating'].max()\n",
    "    return subsetmovie[subsetmovie.rating == maxrating].sample()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simulate with one selector (greedy or random or bayes or ...)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And return scoring"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def reinforcement_learning(user, moviestc, algorithm, s, numberSimulation):\n",
    "    if s<200:\n",
    "        print(\"WARNING : s is really small, movies will get often repeated\")\n",
    "    algorithm = algorithm()\n",
    "    user_features = np.zeros(moviestc.shape[1] - 2)\n",
    "    movies = moviestc.copy()\n",
    "    movies = movies[movies.columns.difference([\"votes\", \"rating\"])]\n",
    "    movies.insert(0, 'last_t', np.ones(movies.shape[0]).astype(np.int64))\n",
    "    movies.insert(0, 't', [i for i in range(movies.shape[0])])\n",
    "    movies.insert(0, 'rating', user.rating)\n",
    "    movies.insert(0, 'Nt', np.zeros(movies.shape[0]))\n",
    "    cumregret = [0]\n",
    "    accuracy_rmse = [0]\n",
    "    avg_rating = [0]\n",
    "    timestamp = []\n",
    "    for t in range(numberSimulation):\n",
    "        now = datetime.datetime.now()\n",
    "        recommandation = algorithm.choice(user_features, movies, t+1, s)\n",
    "        recommandation_features = get_movie_features(recommandation)\n",
    "        user_rating = user.loc[recommandation.index[0]].rating\n",
    "        user_features = algorithm.update_features(user_features, recommandation_features, user_rating, t)\n",
    "        utility = algorithm.compute_utility(user_features, recommandation_features, t, s)\n",
    "        cumregret.append(cumregret[-1] + (user_rating - utility ))\n",
    "        accuracy_rmse.append((user_rating - utility )**2 )\n",
    "        avg_rating.append(user_rating)\n",
    "        movies.loc[movies.index.isin(recommandation.index),'last_t'] = t\n",
    "        movies.loc[movies.index.isin(recommandation.index),'Nt'] += 1\n",
    "        timestamp.append((datetime.datetime.now() - now).total_seconds())\n",
    "    return {'cumregret': cumregret, 'accuracy_rmse':accuracy_rmse, 'avg_rating':avg_rating, 'timediff':timestamp}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simulate many"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def rl_multiple_users(users, movies, algorithms, s=500, N=20, N_USER=50):\n",
    "    def wrapper_rl_one_user(args):\n",
    "        return reinforcement_learning(*args)\n",
    "    results_all = []\n",
    "    users_sample = users[users.user.isin(pd.Series(users.user.unique()).sample(N_USER))].copy()\n",
    "    movies_sample = movies[movies.index.isin(users_sample.index.unique())].copy()\n",
    "    for algo in tqdm(algorithms):\n",
    "        res_algo = []\n",
    "        args = []\n",
    "        for i, name in enumerate(users_sample.user.unique()):\n",
    "            user = users[users.user == name]\n",
    "            movies_user = movies_sample[movies_sample.index.isin(user.index)]\n",
    "            res = reinforcement_learning(user, movies_user, algo, s, N)\n",
    "            res_algo.append(res)\n",
    "        results_all.append(res_algo)\n",
    "    return results_all"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Results"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Select multiple users and algo and plot results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Keep list consistent\n",
    "ALGOS      = [partial(LinUCB, 0.5), greedy_choice_no_t_contentbased, random_choice] #, greedy_choice, random_choice]\n",
    "ALGOS_NAME = ['LinUCB', 'greedy_choice_no_t_contentbased', 'random_choice'] #, 'greedy_choice', 'random_choice']\n",
    "assert(len(ALGOS) == len(ALGOS_NAME))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "METRICS = ['cumregret', 'accuracy_rmse', 'avg_rating', 'timediff']\n",
    "TITLE_GRAPH=['Average cumulative regret for each algorithm', 'Average accuracy for each algorithm', 'Average accuracy for each algorithm', 'Average running time for each algorithm']\n",
    "X_AXIS = ['Cumulative reget', 'Accuracy (root mean square error)', 'Rating', 'Time']\n",
    "assert(len(METRICS) == len(TITLE_GRAPH) == len(X_AXIS))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "%time res = rl_multiple_users(users, movies, ALGOS, N=500, N_USER=5, s=200)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "for metric, tgraph, xaxix in zip(METRICS,TITLE_GRAPH,X_AXIS):\n",
    "    data = []\n",
    "    for algo, algon in enumerate(ALGOS_NAME):\n",
    "        temp = np.average(np.array([i[metric] for i in res[algo]]), axis=0)[1:]\n",
    "        data.append(go.Scatter(\n",
    "            x = list([i for i in range(len(temp))]),\n",
    "            y = temp,\n",
    "            name=algon\n",
    "        ))\n",
    "    layout = dict(title = tgraph,\n",
    "              xaxis = dict(title = tgraph),\n",
    "              yaxis = dict(title = xaxix),\n",
    "    )\n",
    "    fig = dict(data=data, layout=layout)\n",
    "    plotly.offline.iplot(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
